#include "lcd_init.h"
#include "stdio.h"
#include <string.h>
// #include "app.h"
#define Command 0
#define Parameter 1
typedef void (*FunType)(void);
//**********************************write function begin********************************************
void wr_cmd_4spi_8bcs(uint8_t par)
{
    LCD_DCXLow();
    LCD_CSLow();

    LCD_SCLLow();
    if (par & 0x80)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x40)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x20)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x10)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x08)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x04)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x02)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x01)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_CSHigh();
    LCD_DCXHigh();
    HAL_Delay(5);
}
void wr_dat_4spi_8bcs(uint8_t par)
{
    LCD_DCXHigh();
    LCD_CSLow();

    LCD_SCLLow();
    if (par & 0x80)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x40)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x20)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x10)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x08)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x04)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x02)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x01)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_CSHigh();
    LCD_DCXHigh();
    HAL_Delay(1);
}
void wr_cmd_parall1_8(uint16_t par)
{
    LCD_DCXLow();
    LCD_CSLow();
    LCD_WRLow();
    GPIOB->ODR = par;

    LCD_WRHigh();
}
void wr_dat_parall1_8(uint16_t par)
{
    LCD_DCXHigh();
    LCD_WRLow();
    GPIOB->ODR = par;

    LCD_WRHigh();
}
void wr_cmd_parall1_16(uint16_t par)
{
    LCD_DCXLow();
    LCD_CSLow();
    LCD_WRLow();
    GPIOB->ODR = par;

    LCD_WRHigh();
}
void wr_dat_parall1_16(uint16_t par)
{
    LCD_DCXHigh();
    LCD_WRLow();
    GPIOB->ODR = par;

    LCD_WRHigh();
}
void wr_cmd_7775r(uint16_t par)
{
    uint8_t parH = par >> 6;
    uint32_t parL = (par << 10) & 0xFC00;
    LCD_DCXLow();
    LCD_CSLow();
    LCD_WRLow();
    if (parH & 0x02)
        HAL_GPIO_WritePin(DB17_GPIO_Port, DB17_Pin, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(DB17_GPIO_Port, DB17_Pin, GPIO_PIN_RESET);

    if (parH & 0x01)
        HAL_GPIO_WritePin(DB16_GPIO_Port, DB16_Pin, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(DB16_GPIO_Port, DB16_Pin, GPIO_PIN_RESET);

    GPIOB->ODR = parL;

    // LCD_WRHigh();
}

void wr_cmd_parall2_8(uint16_t par)
{
    LCD_DCXLow();
    LCD_CSLow();
    LCD_WRLow();
    GPIOB->ODR = par << 1;

    LCD_WRHigh();
}
void wr_dat_parall2_8(uint16_t par)
{
    LCD_DCXHigh();
    LCD_WRLow();
    GPIOB->ODR = par << 1;

    LCD_WRHigh();
}
//**********************************read function begin********************************************
void pb_out(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // db 0-7
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void pb_in(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // db 0-7
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
uint16_t i801_read_byte(void)
{
    uint16_t v;

    LCD_DCXHigh();
    LCD_RDLow();
    LCD_RDHigh();
    v = GPIOB->IDR;
    // v= v >> 1;
    return v;
}
void rd_parall1_8(uint8_t c, uint16_t *d, uint32_t l)
{
    // uint16_t buf[128];

    wr_cmd_parall1_8(c);
    pb_in();
    // LCD_DCXHigh();
    // LCD_RDLow();
    // LCD_RDHigh();
    for (int i = 0; i < l; i++)
    {
        d[i] = i801_read_byte();
        HAL_Delay(100);
    }
    LCD_CSHigh();
    pb_out();
    // memcpy(d, buf, l);
}
//**********************************write display begin********************************************
void wr_displ_parall1_8(uint8_t color)
{
    LCD_DCXHigh();
    LCD_WRLow();
    GPIOB->ODR = color;
    LCD_WRHigh();
}
void wr_displ_parall2_18(uint16_t color1, uint16_t color2)
{
    LCD_DCXHigh();
    LCD_WRLow();
    if (color1 & 0x02)
        HAL_GPIO_WritePin(DB17_GPIO_Port, DB17_Pin, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(DB17_GPIO_Port, DB17_Pin, GPIO_PIN_RESET);
    if (color1 & 0x01)
        HAL_GPIO_WritePin(DB16_GPIO_Port, DB16_Pin, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(DB16_GPIO_Port, DB16_Pin, GPIO_PIN_RESET);
    GPIOB->ODR = color2;
    LCD_WRHigh();
}

void Write(int com, uint16_t par)
{
    if (com == 0)
    {
        wr_cmd_parall1_8(par);
    }
    else
    {
        wr_dat_parall1_8(par);
    }
}

int read_ID(void)
{
    uint16_t buf[128];
    uint8_t result = 0;
    rd_parall1_8(0x04, buf, 4);
    printf("read 0x04 is %02x,%02x,%02x\n\r", buf[1], buf[2], buf[3]);
    if ((buf[1] == 0x89) & (buf[2] == 0x89) & (buf[3] == 0x77))
    {
        result = 1;
    }
    else if ((buf[1] == 0x81) & (buf[2] == 0x81) & (buf[3] == 0xB3))
    {
        result = 2;
    }
    else
    {
        result = 0;
    }

    printf("read ID result is %d\n\r", result);
    return result;
}

void oHW_Reset(void)
{
    LCD_RSTHigh();
    HAL_Delay(10); // ms
    LCD_RSTLow();
    HAL_Delay(10); // ms
    LCD_RSTHigh();
    HAL_Delay(10); // ms
}

void Delay(uint32_t ms)
{
    HAL_Delay(ms);
}

int read_times(void)
{
    uint16_t buf[128];
    uint8_t result = 0;
    uint8_t reval = 0;

    Write(Command, 0xDF);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0x02);
    Write(Parameter, 0x01);
    rd_parall1_8(0xCA, buf, 2);
    // printf("read CAh is %02x\n\r",buf[1]);
    reval = buf[1];
    if (reval == 0xD5)
    {
        result = 2;
    }
    else if (reval == 0xF5)
    {
        result = 1;
    }
    else if (reval == 0xFD)
    {
        result = 0;
    }
    else
    {
        result = 0;
    }
    printf("read otp times is %d\n\r", result);
    return result;
}

void initial(void)
{
    read_times();
    Delay(120);

    Write(Command, 0x11);

    Delay(120);

    Write(Command, 0xDF);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0x02);
    Write(Parameter, 0x01);

    Write(Command, 0xB2);
    Write(Parameter, 0x0C);
    Write(Parameter, 0x0C);
    Write(Parameter, 0x00);
    Write(Parameter, 0x33);
    Write(Parameter, 0x33);

    Write(Command, 0x35);
    Write(Parameter, 0x00);

    Write(Command, 0x36);
    Write(Parameter, 0x00);

    Write(Command, 0x3A);
    Write(Parameter, 0x06);

    Write(Command, 0xB7);
    Write(Parameter, 0x74);

    Write(Command, 0xBB);
    Write(Parameter, 0x1F);

    Write(Command, 0xC0);
    Write(Parameter, 0x2C);

    Write(Command, 0xC2);
    Write(Parameter, 0x01);

    Write(Command, 0xC3);
    Write(Parameter, 0x19);

    Write(Command, 0xC6);
    Write(Parameter, 0x0F);

    Write(Command, 0xD0);
    Write(Parameter, 0xA7);

    Write(Command, 0xD0);
    Write(Parameter, 0xA4);
    Write(Parameter, 0xA1);

    Write(Command, 0xD6);
    Write(Parameter, 0xA1);

    Write(Command, 0xE0);
    Write(Parameter, 0xF0);
    Write(Parameter, 0x04);
    Write(Parameter, 0x0A);
    Write(Parameter, 0x09);
    Write(Parameter, 0x08);
    Write(Parameter, 0x15);
    Write(Parameter, 0x2D);
    Write(Parameter, 0x44);
    Write(Parameter, 0x45);
    Write(Parameter, 0x3A);
    Write(Parameter, 0x14);
    Write(Parameter, 0x13);
    Write(Parameter, 0x2B);
    Write(Parameter, 0x2F);

    Write(Command, 0xE1);
    Write(Parameter, 0xF0);
    Write(Parameter, 0x05);
    Write(Parameter, 0x08);
    Write(Parameter, 0x07);
    Write(Parameter, 0x06);
    Write(Parameter, 0x02);
    Write(Parameter, 0x2C);
    Write(Parameter, 0x43);
    Write(Parameter, 0x45);
    Write(Parameter, 0x3B);
    Write(Parameter, 0x18);
    Write(Parameter, 0x18);
    Write(Parameter, 0x2C);
    Write(Parameter, 0x31);

    Write(Command, 0x21);

    Write(Command, 0x29);

    Write(Command, 0x2C);
}

void NVM_code(uint8_t addr, uint8_t data)
{
    Write(Command, 0xFA);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0xEE);
    Write(Parameter, 0x84);
    Delay(5);

    Write(Command, 0xFC);
    Write(Parameter, addr);
    Write(Parameter, data);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(5);
}

void OT_program(void)
{
    printf("Step 5. Reset IC and keep in sleep out mode\n\r");
    oHW_Reset();
    Delay(120);
    Write(Command, 0x11);
    Delay(80);

    printf("Step 6. Enable NVM internal VPP program mode\n\r");
    Write(Command, 0xDF);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0x02);
    Write(Parameter, 0x09);
    Delay(100);
    Write(Command, 0xEC);
    Write(Parameter, 0x01);

    printf("Step 7. NVM programming code\n\r");
    NVM_code(0x0D, 0x2C);
    NVM_code(0x0E, 0x89);
    NVM_code(0x0F, 0x89);
    NVM_code(0x10, 0x77);
    NVM_code(0x11, 0x01);
    NVM_code(0x12, 0xFF);
    NVM_code(0x13, 0x0B);
    NVM_code(0x14, 0x20);
    NVM_code(0x15, 0x20);
    NVM_code(0x16, 0x0f);
    NVM_code(0x17, 0x00);
    NVM_code(0x18, 0xE2);

    Write(Command, 0xEC);
    Write(Parameter, 0x00);

    NVM_code(0x01, 0xFD);

    Write(Command, 0xFA);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0xEE);
    Write(Parameter, 0x00);
    Write(Command, 0xDF);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0x02);
    Write(Parameter, 0x00);
}

void fillcolor(uint8_t color_r, uint8_t color_g, uint8_t color_b)
{
    wr_cmd_parall1_8(0x2A);
    wr_dat_parall1_8(0x00);
    wr_dat_parall1_8(0x00);
    wr_dat_parall1_8(0x00);
    wr_dat_parall1_8(0xEF);

    wr_cmd_parall1_8(0x2B);
    wr_dat_parall1_8(0x00);
    wr_dat_parall1_8(0x00);
    wr_dat_parall1_8(0x01);
    wr_dat_parall1_8(0x3F);

    wr_cmd_parall1_8(0x2c);
    for (uint16_t i = 0; i < 320; i++)
    {
        for (uint16_t j = 0; j < 240; j++)
        {
            wr_dat_parall1_8(color_r);
            wr_dat_parall1_8(color_g);
            wr_dat_parall1_8(color_b);
        }
    }
}

void OTP_main(void)
{
    uint16_t result_ID = 0;
    oHW_Reset();
    result_ID = read_ID();
    initial();
    if (result_ID != 1)
    {
        fillcolor(0x00, 0x00, 0x00);
        printf("begin OTP\n\r");
        OT_program();
        HAL_GPIO_WritePin(CTRL_VCC_GPIO_Port, CTRL_VCC_Pin, GPIO_PIN_RESET);
        Delay(200);
        HAL_GPIO_WritePin(CTRL_VCC_GPIO_Port, CTRL_VCC_Pin, GPIO_PIN_SET);

        oHW_Reset();
        result_ID = read_ID();
        initial();
        if (result_ID != 1)
        {
            printf("OTP NG\n\r");
            fillcolor(0xFF, 0x00, 0x00);
            while (1)
            {
                Delay(100);
            }
        }
        else
        {
            printf("OTP OK\n\r");
            fillcolor(0x00, 0xFF, 0x00);
            Delay(1000);
        }
    }
    else
    {
        printf("has been OTP\n\r");
        fillcolor(0x00, 0xFF, 0x00);
        Delay(1000);
    }
}
